﻿using System;
using System.Collections.Generic;
using System.Linq;

namespace Cms.Domain
{
    public class Menu : ICloneable, IComparable<Menu>
    {
        private string _activeItemPrefix;
        private string _description;
        private int _extraWrapperSpans;
        private bool _itemIsActiveWhenSubItemIsActive;
        private string _name;
        private MenuVersion _publishedVersion;
        private Site _site;
        private SourceCode _styleSheet;
        private SubMenuBehaviour _subMenuBehaviour;
        private IList<MenuVersion> _versions;

        public Menu()
        {
            _versions = new List<MenuVersion>();
            _extraWrapperSpans = 0;
        }

        private Menu(Menu original)
            : this()
        {
            _name = original.Name;
            _description = original.Description;
            _itemIsActiveWhenSubItemIsActive = original.ItemIsActiveWhenSubItemIsActive;
            _subMenuBehaviour = original.SubMenuBehaviour;
            _activeItemPrefix = original.ActiveItemPrefix;
            _site = original.Site;
            _site.Menus.Add(this);
            _styleSheet = (SourceCode)original.StyleSheet.Clone();
            _publishedVersion = (MenuVersion)original.PublishedVersion.Clone();
            _publishedVersion.Parent = this;
            _versions.Add(_publishedVersion);
        }
        
        public virtual int ID { get; set; }

        public virtual string Name
        {
            get { return _name; }
            set { _name = value; }
        }
        
        public virtual string Description
        {
            get { return _description; }
            set { _description = value; }
        }
        
        public virtual Site Site
        {
            get { return _site; }
            set { _site = value; }
        }
        
        public virtual IList<MenuVersion> Versions
        {
            get { return _versions; }
            set { _versions = value; }
        }

        public virtual MenuVersion PublishedVersion
        {
            get { return _publishedVersion; }
            set { _publishedVersion = value; }
        }

        public virtual SourceCode StyleSheet
        {
            get { return _styleSheet; }
            set { _styleSheet = value; }
        }

        public virtual bool ItemIsActiveWhenSubItemIsActive
        {
            get { return _itemIsActiveWhenSubItemIsActive; }
            set { _itemIsActiveWhenSubItemIsActive = value; }
        }
        
        public virtual SubMenuBehaviour SubMenuBehaviour
        {
            get { return _subMenuBehaviour; }
            set { _subMenuBehaviour = value; }
        }
        
        public virtual string ActiveItemPrefix
        {
            get { return _activeItemPrefix; }
            set { _activeItemPrefix = value; }
        }

        public virtual int ExtraWrapperSpans
        {
            get { return _extraWrapperSpans; }
            set { _extraWrapperSpans = value; }
        }

        #region ICloneable Members

        public virtual object Clone()
        {
            return new Menu(this);
        }

        #endregion

        public virtual string GetStyleSheetCode()
        {
            return _styleSheet != null ? _styleSheet.CurrentVersion.Code : string.Empty;
        }

        public virtual void SetStyleSheetCode(string code, Administrator editedBy)
        {
            if (_styleSheet == null)
                _styleSheet = new SourceCode { Site = _site };
            _styleSheet.AddVersion(code, editedBy);
        }

        public virtual MenuVersion GetVersion(int id)
        {
            return _versions.FirstOrDefault(v => v.ID == id);
        }
        
        public virtual void RemoveImage(MediaFile image)
        {
            foreach (var kvp in
                _versions.SelectMany(version => version.Items.SelectMany(item => item.Translations)))
            {
                if (kvp.Value.DefaultImage != null && kvp.Value.DefaultImage.ID == image.ID)
                    kvp.Value.DefaultImage = null;
                if (kvp.Value.DefaultHoverImage != null && kvp.Value.DefaultHoverImage.ID == image.ID)
                    kvp.Value.DefaultHoverImage = null;
                if (kvp.Value.ActiveImage != null && kvp.Value.ActiveImage.ID == image.ID)
                    kvp.Value.ActiveImage = null;
                if (kvp.Value.ActiveHoverImage != null && kvp.Value.ActiveHoverImage.ID == image.ID)
                    kvp.Value.ActiveHoverImage = null;
            }
        }
        
        public virtual IList<int> CleanExpandedIDs(Page activePage, IList<int> expandedIDs)
        {
            if (activePage == null)
                return expandedIDs;

            // Figure out which menu item is active
            MenuItem activeItem = null;
            foreach (MenuItem item in _publishedVersion.Items)
            {
                if (item.Page == null)
                    continue;
                if (activePage.ID == item.Page.ID ||
                    (item.ActiveForPagesInCategory != null && item.ActiveForPagesInCategory.ContainsPage(activePage)))
                {
                    activeItem = item;
                    break;
                }
            }
            if (activeItem == null)
                return expandedIDs;

            // Remove all items that are not children of the active item
            int i = 0;
            while (i < expandedIDs.Count)
            {
                MenuItem mi = _publishedVersion.GetItem(expandedIDs[i]);
                if (activeItem.IsParentTo(mi))
                    i++;
                else
                    expandedIDs.RemoveAt(i);
            }

            // Add all parent IDs of the active item to the expandedIDs collection
            MenuItem parent = activeItem.Parent;
            while (parent != null)
            {
                if (!expandedIDs.Contains(parent.ID))
                    expandedIDs.Add(parent.ID);
                parent = parent.Parent;
            }
            return expandedIDs;
        }

        public virtual int CompareTo(Menu other)
        {
            return this.ID > 0 && this.ID == other.ID ? 0 : 1;
        }

        public override bool Equals(object obj)
        {
            Menu other = (Menu)obj;
            if (this.ID != other.ID)
                return false;
            if (this.ID > 0 && this.ID == other.ID)
                return true;
            return ReferenceEquals(this, obj);
        }

        public override int GetHashCode()
        {
            return this.ID.GetHashCode();
        }
    }
}